
package org.example.baseinfo.service.impl;


import com.alibaba.fastjson.JSON;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.example.baseinfo.common.page.HxPage;
import org.example.baseinfo.common.page.HxPageRequest;
import org.example.baseinfo.common.vo.BaseResponse;
import org.example.baseinfo.pojo.vo.school.*;
import org.example.baseinfo.entity.SchoolEntity;
import org.example.baseinfo.repository.ISchoolRepository;
import org.example.baseinfo.service.IAsyncMqService;
import org.example.baseinfo.service.ISchoolService;
import lombok.extern.slf4j.Slf4j;
import org.example.baseinfo.util.DateUtils;
import org.example.baseinfo.util.JsonUtil;
import org.example.baseinfo.util.PinyinUtil;
import org.example.baseinfo.util.RedisUtil;
import org.hibernate.query.NativeQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class SchoolServiceImpl implements ISchoolService {

    @Resource
    private ISchoolRepository schoolRepository;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private IAsyncMqService asyncMqService;

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String save(SaveSchoolReqVO param) {
        SchoolEntity entity;
        //学校code处理
        String organCode = PinyinUtil.getPinyin(param.getSchoolName());
        // 参数校验：以学校名称拼音首字母作为唯一识别
        SchoolEntity schoolEntity = schoolRepository.findByDeleteStatusAndSchoolCode(Short.valueOf("1"),organCode);
        if (schoolEntity != null) {
            //如果拼音做code已存在，则在后面添加随机数
            param.setSchoolCode(organCode+String.valueOf((int)(Math.random()*10000)));
        }else {
            param.setSchoolCode(organCode);
        }
        // 数据保存
        entity = new SchoolEntity();
        BeanUtils.copyProperties(param, entity);
        schoolRepository.save(entity);
        // 发送同步消息
        asyncMqService.sendSchoolInfoMessage(param.getSchoolCode());
        return entity.getSchoolId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UpdateSchoolReqVO param) throws Exception {
        // 参数校验
        SchoolEntity schoolEntity = schoolRepository.findByIdAndDeleteStatus(param.getSchoolId(),Short.valueOf("1"));
        if (schoolEntity == null) {
            throw new Exception("学校不存在");
        }
        // 数据保存
        BeanUtils.copyProperties(param, schoolEntity);
        schoolEntity.setUpdateDatetime(DateUtils.getCurrentDateToString());

        redisUtil.del(schoolEntity.getSchoolId());

        asyncMqService.saveSchoolChangeLog(schoolEntity,param.getUpdateUser(),"后台管理修改");
        schoolRepository.save(schoolEntity);
        // 发送同步消息
        asyncMqService.sendSchoolInfoMessage(schoolEntity.getSchoolCode());

        redisUtil.del(schoolEntity.getSchoolId());
    }


    @Override
    public SchoolVO query(QuerySchoolReqVO param) {
        SchoolEntity entity = null;
        if (StringUtils.isNotBlank(param.getSchoolCode())){
            entity = schoolRepository.findByDeleteStatusAndSchoolCode(Short.valueOf("1"),param.getSchoolCode());
        }else if (StringUtils.isNotBlank(param.getSchoolId())){
            String s = redisUtil.get(param.getSchoolId());
            if (s != null){
                entity = JSON.parseObject(s, SchoolEntity.class);
            }else {
                entity = schoolRepository.findByIdAndDeleteStatus(param.getSchoolId(),Short.valueOf("1"));
                redisUtil.set(param.getSchoolId(), JsonUtil.convertObject(entity));
            }
        }else if (StringUtils.isNotBlank(param.getSchoolName())){
            entity = schoolRepository.findBySchoolNameLikeAndDeleteStatus(param.getSchoolName(),Short.valueOf("1"));
        }
        if (entity != null){
            SchoolVO vo = new SchoolVO();
            BeanUtils.copyProperties(entity,vo);
            return vo;
        }else {
            return new SchoolVO();
        }

    }


    @Override
    public List<SchoolVO> list(QuerySchoolListReqVO reqVO) {

        //查询返回内容
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT s.school_id as schoolId,s.school_name as schoolCode,s.school_code as schoolName" +
                " FROM school s " +
                " WHERE s.delete_status = 1 ");
        if (StringUtils.isNotEmpty(reqVO.getSchoolCode())) {
            sql.append(" AND s.school_code = :schoolCode ");
        }

        if (StringUtils.isNotEmpty(reqVO.getSchoolName())) {
            sql.append(" AND s.school_name like :schoolName ");
        }
        sql.append(" ORDER BY s.create_datetime desc ");
        Query query = entityManager.createNativeQuery(sql.toString());

        if (StringUtils.isNotEmpty(reqVO.getSchoolCode())) {
            query.setParameter("schoolCode", reqVO.getSchoolCode());
        }

        if (StringUtils.isNotEmpty(reqVO.getSchoolName())) {
            query.setParameter("schoolName", "%" + reqVO.getSchoolName() + "%");
        }


        List<Object> listCount = query.getResultList();


        if (listCount.isEmpty()) {
            List<SchoolVO> result = new ArrayList<>();
            return result;
        }

        query.unwrap(NativeQuery.class).setResultTransformer(Transformers.aliasToBean(SchoolVO.class));
        List<SchoolVO> list = query.getResultList();
        return list;

    }


    @Override
    public HxPage<SchoolVO> page(HxPageRequest<QuerySchoolListReqVO> pageRequest) {
        HxPage<SchoolVO> resultPage = new HxPage<>();
        QuerySchoolListReqVO reqVO = pageRequest.getQuery();
        List<SchoolVO> resultList = new ArrayList<>();
        Page<SchoolEntity> page = schoolRepository
                .findAll((Root<SchoolEntity> root, CriteriaQuery<?> query, CriteriaBuilder cd) -> {
                    List<Predicate> filters = new ArrayList<>();
                    filters.add(cd.equal(root.get("deleteStatus"), Short.valueOf("1")));
                    if(StringUtils.isNotBlank(reqVO.getSchoolCode())){
                        filters.add(cd.equal(root.get("schoolCode"), reqVO.getSchoolCode()));
                    }
                    if(StringUtils.isNotBlank(reqVO.getSchoolName())){
                        filters.add(cd.like(root.get("schoolName"), "%"+reqVO.getSchoolName()+"%"));
                    }
                    query.where(filters.toArray(new Predicate[filters.size()]));
                    return null;
                }, PageRequest.of(pageRequest.getPageNum() - 1, pageRequest.getPageSize()));
        List<SchoolEntity> list = page.getContent();
        if (list.size() == 0) {
            resultPage.setContent(new ArrayList<>());
            return null;
        }
        for (SchoolEntity entity : list) {
            SchoolVO resVO = new SchoolVO();
            BeanUtils.copyProperties(entity, resVO);
            resultList.add(resVO);
        }
        long count = page.getTotalElements();
        resultPage.setTotalPages((int) count);
        resultPage.setContent(resultList);
        resultPage.setPageNum(resultPage.getPageNum());
        resultPage.setPageSize(page.getSize());
        resultPage.setTotalPages(page.getTotalPages());
        resultPage.setAsc(false);
        return resultPage;
    }

    @Override
    public void syn() {
        List<SchoolEntity> list = schoolRepository.findByDeleteStatus(Short.valueOf("1"));
        for(SchoolEntity schoolEntity :list){
            // 发送同步消息
            asyncMqService.sendSchoolInfoMessage(schoolEntity.getSchoolCode());
        }
    }


}
